package ipx

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"math/rand/v2"
	"net/http"
	"strings"
	"time"

	"gitee.com/burningsong/golib/pkg/gox"
)

// HTTPIpGetter 通过 HTTP 请求获取 IP
type HTTPIpGetter struct {
	URL     string
	Timeout time.Duration
}

// NewHTTPIpGetter 创建一个新的 HTTPIpGetter
func NewHTTPIpGetter(url string) *HTTPIpGetter {
	return &HTTPIpGetter{
		URL:     url,
		Timeout: 5 * time.Second,
	}
}

// GetMyIP 通过 HTTP 请求获取公网 IP
func (g *HTTPIpGetter) GetMyIP(ctx context.Context) (string, error) {
	ctx, cancel := context.WithTimeout(ctx, g.Timeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, g.URL, nil)
	if err != nil {
		return "", fmt.Errorf("failed to create request: %w", err)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("HTTP status code error: %d", resp.StatusCode)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read response: %w", err)
	}

	// 清理返回的 IP 地址（移除空格和换行符）
	ip := strings.TrimSpace(string(body))
	if ip == "" {
		return "", fmt.Errorf("got empty IP")
	}

	return ip, nil
}

// 特殊的 IP 获取适配器

// JSONIpGetter 从返回 JSON 的服务中提取 IP
type JSONIpGetter struct {
	URL       string
	Timeout   time.Duration
	FieldPath string // JSON 路径，例如 "ip" 或 "data.ip"
}

// NewJSONIpGetter 创建一个新的 JSON IP 获取器
func NewJSONIpGetter(url, fieldPath string) *JSONIpGetter {
	return &JSONIpGetter{
		URL:       url,
		Timeout:   5 * time.Second,
		FieldPath: fieldPath,
	}
}

// GetMyIP 从 JSON 响应中提取 IP
func (g *JSONIpGetter) GetMyIP(ctx context.Context) (string, error) {
	client := &http.Client{
		Timeout: g.Timeout,
	}

	ctx, cancel := context.WithTimeout(ctx, g.Timeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, g.URL, nil)
	if err != nil {
		return "", fmt.Errorf("failed to create request: %w", err)
	}

	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to request JSON service: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("JSON service returned error status code: %d", resp.StatusCode)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read JSON response: %w", err)
	}

	// 解析 JSON
	var result map[string]interface{}
	if err := json.Unmarshal(body, &result); err != nil {
		return "", fmt.Errorf("failed to parse JSON response: %w", err)
	}

	// 提取 IP 字段
	if ip, ok := result[g.FieldPath].(string); ok {
		if ip == "" {
			return "", fmt.Errorf("IP field is empty in JSON response")
		}
		return ip, nil
	}

	return "", fmt.Errorf("IP field not found in JSON response: %s", g.FieldPath)
}

// CombinedIpGetter 组合多个 IP 获取器，并比较结果
type CombinedIpGetter struct {
	Getters []IpGetter
	Config  IpGetterConfig
}

// NewCombinedIpGetter 创建一个组合 IP 获取器
func NewCombinedIpGetter(getters []IpGetter, config IpGetterConfig) (*CombinedIpGetter, error) {
	if config.MinConsensusCount > len(getters) {
		return nil, fmt.Errorf("consensusCount is greater than number of getters")
	}

	return &CombinedIpGetter{
		Getters: getters,
		Config:  config,
	}, nil
}

// GetMyIP 组合多个 IP 获取器，并比较结果
func (g *CombinedIpGetter) GetMyIP(ctx context.Context) (string, error) {
	if len(g.Getters) == 0 {
		return "", fmt.Errorf("no IP getters configured")
	}

	// 准备获取器列表
	var getters []IpGetter
	if isShuffle(g.Config.ShuffleGetterProbability) {
		getters = make([]IpGetter, len(g.Getters))
		copy(getters, g.Getters)
		shuffle(getters)
	} else {
		getters = g.Getters
	}

	// 设置并发数（至少为1，最多为getters的数量）
	concurrency := g.Config.Concurrency
	if concurrency < 1 {
		concurrency = 1
	}
	if concurrency > len(getters) {
		concurrency = len(getters)
	}

	// 针对并发数为1的特殊情况进行简化处理
	if concurrency == 1 {
		return g.getMyIPSequentially(ctx, getters)
	}

	// 使用 errgroup 实现的共识运行器
	// 创建IP获取任务列表
	tasks := make([]gox.Task[string], len(getters))
	for i, getter := range getters {
		getter := getter // 捕获变量
		tasks[i] = func(ctx context.Context) (string, error) {
			return getter.GetMyIP(ctx)
		}
	}

	ip, err := gox.RunUntilConsensus(ctx, tasks,
		gox.WithConcurrency[string](concurrency),
		gox.WithMinConsensus[string](g.Config.MinConsensusCount),
	)

	return ip, err
}

// getMyIPSequentially 当并发度为1时，顺序执行获取IP操作
func (g *CombinedIpGetter) getMyIPSequentially(ctx context.Context, getters []IpGetter) (string, error) {
	// 用于记录结果和出现次数
	results := make(map[string]int)
	var lastErr error

	// 顺序尝试每个获取器
	for _, getter := range getters {
		ip, err := getter.GetMyIP(ctx)
		if err != nil {
			lastErr = err
			continue
		}

		if ip == "" {
			continue
		}

		// 计数当前IP出现次数
		results[ip]++

		// 如果达到共识阈值，立即返回结果
		if results[ip] >= g.Config.MinConsensusCount {
			return ip, nil
		}

		// 检查是否还可能达到共识
		remainingGetters := len(getters) - len(results)
		canReachConsensus := false

		for _, count := range results {
			if count+remainingGetters >= g.Config.MinConsensusCount {
				canReachConsensus = true
				break
			}
		}

		if !canReachConsensus {
			break
		}
	}

	// 如果有任何结果，返回出现次数最多的
	if len(results) > 0 {
		var maxIP string
		var maxCount int

		for ip, count := range results {
			if count > maxCount {
				maxCount = count
				maxIP = ip
			}
		}

		return maxIP, nil
	}

	// 所有获取器都失败
	if lastErr != nil {
		return "", fmt.Errorf("all IP getters failed: %w", lastErr)
	}

	return "", fmt.Errorf("no valid IP found")
}

func isShuffle(probability float64) bool {
	if probability <= 0 {
		return false
	}
	if probability >= 1 {
		return true
	}
	r := rand.New(rand.NewPCG(uint64(time.Now().UnixNano()), uint64(time.Now().UnixNano()>>32)))
	return r.Float64() < probability
}

// shuffle 函数用于随机打乱切片顺序
func shuffle(getters []IpGetter) {
	// 创建一个新的PCG生成器
	r := rand.New(rand.NewPCG(uint64(time.Now().UnixNano()), uint64(time.Now().UnixNano()>>32)))
	r.Shuffle(len(getters), func(i, j int) {
		getters[i], getters[j] = getters[j], getters[i]
	})

}
